package com.application.net;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Map;

import com.application.appenum.ESB_TYPE;
import com.application.appenum.NET_TYPE;
import com.application.common.BaseContext;
import com.application.common.BaseLogger;
import com.application.config.BaseConfig;
import com.application.iface.IHandle;
import com.application.iface.IMessage;
import com.application.iface.IPacket;



public class TcpConnect extends Thread implements Runnable {
	protected String ip;
	protected int port;
	protected int timeout;
	protected boolean isAvail = false;
	protected int weight;                           //负载指标
	protected Socket socket;
	protected String packetClazName = "JsonPacket"; //默认JSON报文
	protected String msgClazName = "StdMessage";     //默认标准格式  sys app content
	protected String handleClazName = "DefaultHandle";
	
	protected NET_TYPE netType;                     //网络类型

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public int getTimeout() {
		return timeout;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public boolean isAvail() {
		return isAvail;
	}

	public void setAvail(boolean isAvail) {
		this.isAvail = isAvail;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	public NET_TYPE getNetType() {
		return netType;
	}

	public void setNetType(NET_TYPE netType) {
		this.netType = netType;
	}

	public String getPacketClazName() {
		return packetClazName;
	}

	public void setPacketClazName(String packetClazName) {
		this.packetClazName = packetClazName;
	}

	public String getMsgClazName() {
		return msgClazName;
	}

	public void setMsgClazName(String msgClazName) {
		this.msgClazName = msgClazName;
	}

	public String getHandleClazName() {
		return handleClazName;
	}

	public void setHandleClazName(String handleClazName) {
		this.handleClazName = handleClazName;
	}

	/**
	 * 获取报文-根据配置获取报文类型
	 * @throws Exception 
	 */
	public IPacket getPacket() throws Exception{
		Map<String,IPacket> allPacket = BaseContext.context.getBeansOfType(IPacket.class);
		if(allPacket == null){
			throw new Exception("没有注册报文类型");
		}
		
		for(IPacket p :allPacket.values()){
			if(p.getClass().getSimpleName().equals(this.packetClazName)){
				return p;
			}
		}
		
		throw new Exception("没有类名为(" + this.packetClazName + ")的报文类型");
	}

	public IHandle getHandle() throws Exception{
		Map<String,IHandle> allPacket = BaseContext.context.getBeansOfType(IHandle.class);
		if(allPacket == null){
			throw new Exception("没有注册报文类型");
		}
		
		for(IHandle p :allPacket.values()){
			BaseLogger.writeDebugLog(p.getClass().getSimpleName());
			if(p.getClass().getSimpleName().equals(this.handleClazName)){
				return p;
			}
		}
		
		throw new Exception("没有类名为(" + this.handleClazName + ")的操作类");
	}
	
    public void runServer(){
    	ServerSocket serverSocket = null;
    	boolean runFlg = true;
    	try {
    		BaseLogger.writeLog("I", "启动监听 IP:" +  this.getIp() + " 端口："+ this.getPort());
			serverSocket = new ServerSocket(this.getPort());
			while (runFlg) {
				Socket socket = null;
				String reqStr = "";
				try {
					socket = serverSocket.accept();
					ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
					
					reqStr = (String) ois.readObject();
					try {
						// 根据配置获取报文类型
						IPacket pack = getPacket();
						// 根据配置获取报文格式
						IMessage msg = pack.getMessage(msgClazName,reqStr);
						// 根据格式分发处理
						IHandle handle = getHandle();
						handle.handle(pack,msg);
					} catch (Exception e) {
						BaseLogger.writeLog("E", e.getMessage());
					}finally{						
						socket.close();
					}
					
				} catch (ClassNotFoundException e) {
					BaseLogger.writeLog("E", "Open socket server error");
				}finally{
					if(socket!=null){
						socket.close();
					}					
				}
			}			
		} catch (IOException e) {
			BaseLogger.writeLog("E", "Open socket server error");
		}finally {
			if (serverSocket != null) {
				try {
					serverSocket.close();
				} catch (IOException e) {
					BaseLogger.writeLog("E", "Close socket server error");
				} finally {
					serverSocket = null;
				}
			}
		}
    }
    public void runClient(String data) throws Exception{
		try {
			this.socket = new Socket(this.ip,this.port);
		} catch (UnknownHostException e) {
			BaseLogger.writeLog("E", "HOST ERROR " + this.ip + ":"+this.port+ " " + e.getMessage());
			throw new Exception(e);
		} catch (IOException e) {
			BaseLogger.writeLog("E", "HOST ERROR " + this.ip + ":"+this.port+ " " + e.getMessage());
			throw new Exception(e);
		}
    	try {
			this.socket.setSoTimeout(this.timeout);
		} catch (SocketException e) {
			BaseLogger.writeLog("E", "set timeout error " + this.ip + ":"+this.port+ " " + e.getMessage());
			throw new Exception(e);
		}
    	ObjectOutputStream oos = null;
    	try {
			oos = new ObjectOutputStream(socket.getOutputStream());
			oos.writeObject(data);
			oos.flush();
		} catch (IOException e) {
			BaseLogger.writeLog("E", "Send ERROR " + this.ip + ":"+this.port + " " + e.getMessage());
			throw new Exception(e);
		} finally{
			try {
				oos.close();
			} catch (IOException e) {
				BaseLogger.writeLog("E", "close ObjectOutputStream ERROR " + this.ip + ":"+this.port + " " + e.getMessage());
			}
			
			try {
				socket.close();
			} catch (IOException e) {
				BaseLogger.writeLog("E", "close socket ERROR " + this.ip + ":"+this.port + " " + e.getMessage());
			}
		}

    	
    }
	public void run() {
		if(ESB_TYPE.CLIENT.getKey().equals(BaseConfig.getInstance().getEsbType())){
			if(NET_TYPE.CLIENT.equals(netType)){
				
			}else{
				runServer();
			}			
		}
	}	
}
